#include "testclient.h"
#include "bankclienttestcase.h"
#include <algorithm>
#include <QMutexLocker>
#include <QApplication>
#include <QMetaType>
#include <QtConcurrent/QtConcurrent>

bool testCaseBalanceInquiry();

TestClient::TestClient(QObject *parent)
    : QObject(parent),runtimes_(0),finishedCount_(0)
{
    //注册元数据
    //qRegisterMetaType<TestClient>("TestClient");
    //qRegisterMetaType<TestClient>("TestClient&");
    testCaseList_ << "TestBalanceInquiry";
    funcMap_.insert(make_pair(testCaseList_[0],
        bind(&testCaseBalanceInquiry)));
}

void
TestClient::testCaseTask()
{
    //直接进行查询操作，当然实际使用是不安全的，
    //最好是在服务端建立一个临时连接hash map来
    //防止信息泄露
    //运行满足够次数就停止
    int transSuccess = 0,transFailure = 0;
    QTime runAllTime,runOnceTime;
    map<QString,testFunc>::const_iterator it = \
                funcMap_.find(curTestCaseName_);
    elapsedTimeVec_.resize(runtimes_);
    runAllTime.start();
    for(quint64 i = 0;i < runtimes_;++i) {
        //记录最大的传输时间和最小的传输时间
        runOnceTime.start();
        if(it->second()) {
            transSuccess++;
        } else {
            transFailure++;
        }
        elapsedTimeVec_.push_back(runOnceTime.elapsed());
    }
    //记录运行时间，事物成功失败次数
    /*
     * Transactions(transTotal):                  25000 hits
        Availability:                 100.00 %
        Elapsed time(totalTime):                  65.52 secs  这个直接取客户端中花费时间最大的作为平均时间
        Data transferred:              83.65 MB 这个暂时不计算，涉及到获取数据流量信息
        Response time:                  0.57 secs
        Transaction rate:             381.56 trans/sec
        Throughput:                     1.28 MB/sec 这个暂时不计算，涉及到获取数据流量信息
        Concurrency:                  216.02
        Successful transactions(transSuccess):       21707
        Failed transactions(transFailure):               0
        Longest transaction(maxTransTime):            5.83
        Shortest transaction(minTransTime):           0.00
    */
    QString msg;
    //时间都是以ms为单位
    msg.sprintf("totalTime:%d,transSuccess:%d,transFailure:%d,"
                "maxTransTime:%d,minTransTime:%d",
                runAllTime.elapsed(),transSuccess,transFailure,
                *max_element(elapsedTimeVec_.begin(),elapsedTimeVec_.end()),
                *min_element(elapsedTimeVec_.begin(),elapsedTimeVec_.end()));
    statisticTestData(msg);
}

void
TestClient::statisticTestData(QString &msg)
{
    //这里是在子线程中运行，应该如何发送消息到主线程中？
    //还是用锁将其记录到本身这里，当记录完成发送信号到UI中
    QMutexLocker locker(&mutex_);
    testRes_.push_back(msg);
}

void
TestClient::statisitcFineshedTest()
{
    //这里就进行自增操作，达到规定的数量上限就进行信号发送通知UI进行处理。
    finishedCount_++;
    if(finishedCount_ == cliNum_) {
        //可以进行处理，生成UI需要的数据格式后发送
        //emit
        /*
         * Availability:                 100.00 %
            Response time:                  0.57 secs
            Transaction rate:             381.56 trans/sec
            Concurrency:                  216.02

            Availability = success trans / total trans
            Response time = alltotaltime / total trans
            Transaction rate = total trans / balance alltotaltime
            Concurrency = alltotaltime / elapse time
        */
        double availability = 0.0f;
        int allTotalTime = 0;
        int allTransSuccess = 0;
        int allTransFailure = 0;
        double responseTime = 0.0f;
        double transRate = 0.0f;
        double concurrency = 0.0f;
        int totalTime = 0;
        int totalTimeMax = 0;
        int transSuccess = 0;
        int transFailure = 0;
        int maxTransTime = 0;
        int minTransTime = 0x7fffffff;
        QStringList rList,eList;
        QString res;
        vector<QString>::const_iterator it;
        QStringList::const_iterator it2;
        for(it = testRes_.begin();
            it != testRes_.end();++it) {
            rList.clear();
            res = *it;
            rList = res.split(',');
            for(it2 = rList.begin();it2 != rList.end();++it2) {
                eList.clear();
                res = *it2;
                eList = res.split(':');
                if(eList[0] == "totalTime") {
                    totalTime = eList[1].toInt();
                    totalTimeMax = (totalTimeMax < \
                        totalTime) ? totalTime : totalTimeMax;
                } else if(eList[0] == "transSuccess") {
                    transSuccess = eList[1].toInt();
                } else if(eList[0] == "transFailure") {
                    transFailure = eList[1].toInt();
                } else if(eList[0] == "maxTransTime") {
                    if(maxTransTime < eList[1].toInt()) {
                        maxTransTime = eList[1].toInt();
                    }
                } else if(eList[0] == "minTransTime") {
                    if(minTransTime > eList[1].toInt()) {
                        minTransTime = eList[1].toInt();
                    }
                }
            }
            allTotalTime += totalTime;
            allTransSuccess += transSuccess;
            allTransFailure += transFailure;
        }
        availability = (double)(allTransSuccess * 100) / (double)(cliNum_ * runtimes_);
        responseTime = (double)allTotalTime / (double)(cliNum_ * cliNum_ * runtimes_);
        transRate = (double)(cliNum_ * runtimes_) / (double)(allTotalTime / cliNum_);
        concurrency = (double)allTotalTime / (double)totalTimeMax;
        QString statisticRes;
        statisticRes.sprintf("transTotal:%lld,availability:%f%%,elapsedTime:%d,"
                             "responseTime:%f,transRate:%f,concurrency:%f,"
                             "transSuccess:%d,transFailure:%d,maxTransTime:%d,"
                             "minTransTime:%d",
                             cliNum_ * runtimes_,availability,totalTimeMax,responseTime,
                             transRate,concurrency,allTransSuccess,allTransFailure,maxTransTime,
                             minTransTime);
        emit sendStatisticMsg(statisticRes);
    }
}

void
TestClient::runTestCase(QString &name)
{
    map<QString,testFunc>::const_iterator it = funcMap_.find(name);
    if(it != funcMap_.end()) {
        testRes_.clear();
        curTestCaseName_ = name;
        fWatcherVec_.resize(cliNum_);//需要设置和客户端一样多的监听
        for(quint64 i = 0;i < cliNum_;++i) {
            QFuture<void> future_ = QtConcurrent::run(bind(&TestClient::testCaseTask,this));
            //跑完就发送一次信号，然后这里记录跑完线程的数量，全部跑完就发送信号到界面
            QSharedPointer<QFutureWatcher<void> > fWatcherPtr_(new QFutureWatcher<void>);
            connect(fWatcherPtr_.data(),SIGNAL(finished()),this,SLOT(statisitcFineshedTest()));
            fWatcherPtr_->setFuture(future_);
            fWatcherVec_[i] = fWatcherPtr_;
        }
    }
}

Q_DECLARE_METATYPE(TestClient)
